#
# Copyright 2018, Data61, CSIRO (ABN 41 687 119 230)
#
# SPDX-License-Identifier: BSD-2-Clause
#

cmake_minimum_required(VERSION 3.7.2)
project(libpicotcp NONE)

include(external-project-helpers)

set(configure_string "")

config_option(LibPicotcp LIB_PICOTCP "Build libpicotcp" DEFAULT OFF)
config_option(
    LibPicotcpBsd
    LIB_PICOTCP_BSD
    "Build libpicotcp with bsd socket support"
    DEFAULT
    OFF
    DEPENDS
    LibPicotcp
)
mark_as_advanced(LibPicotcp LibPicotcpBsd)
add_config_library(picotcp "${configure_string}")

if(LibPicotcp)
    # find pico tcp location
    find_file(PICOTCP_PATH picotcp PATHS ${CMAKE_SOURCE_DIR}/projects CMAKE_FIND_ROOT_PATH_BOTH)
    mark_as_advanced(FORCE PICOTCP_PATH)
    if("${PICOTCP_PATH}" STREQUAL "PICOTCP_PATH-NOTFOUND")
        message(
            FATAL_ERROR "Failed to find picotcp. Consider cmake -DPICOTCP_PATH=/path/to/picotcp"
        )
    endif()

    # extract compiler args from cmake
    get_property(compile_options DIRECTORY PROPERTY COMPILE_OPTIONS)
    separate_arguments(cmake_c_flags_sep NATIVE_COMMAND "${CMAKE_C_FLAGS}")
    list(APPEND compile_options "${cmake_c_flags_sep}")

    # add the location of muslc headers to the cflags
    string(
        APPEND compile_options
        " -I$<JOIN:$<TARGET_PROPERTY:muslc,INTERFACE_INCLUDE_DIRECTORIES>, -I>"
    )

    if (CMAKE_C_COMPILER_ID STREQUAL "Clang")
        list(APPEND compile_options "${CMAKE_C_COMPILE_OPTIONS_TARGET}${CMAKE_C_COMPILER_TARGET}")
        set(C_COMPILER clang)
    else()
        set(C_COMPILER ${CROSS_COMPILER_PREFIX}gcc)
    endif()

    if (NOT "${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
        set(perf_flags "\"PERF=1\" \"DEBUG=0\"")
    endif()
    # generate a build.sh script to avoid nasty escape issues, we then invoke this in ExternalProject_Add
    file(
        GENERATE
        OUTPUT
        "${CMAKE_CURRENT_BINARY_DIR}/picotcp_external/picotcp/build.sh"
        CONTENT
        "${CMAKE_COMMAND} -E env \
        \"PLATFORM_CFLAGS=$<JOIN:${compile_options}, >\" \
        \"CROSS_COMPILE=${CROSS_COMPILER_PREFIX}\" \
        \"C_COMPILER=${C_COMPILER}\" \
        ${perf_flags} \
        make -s -j"
    )

    add_custom_target(get_muslc)
    add_dependencies(get_muslc muslc)

    # build picotcp using its very own build system
    include(ExternalProject)
    ExternalProject_Add(
        picotcp_external
        SOURCE_DIR
        "picotcp_external"
        DOWNLOAD_COMMAND
        rsync
        -qur
        --exclude='.git'
        ${PICOTCP_PATH}
        <SOURCE_DIR>
        UPDATE_COMMAND
        ""
        PATCH_COMMAND
        sed
        -i
        "s/(CROSS_COMPILE)gcc/(C_COMPILER)/g"
        picotcp/Makefile
        CONFIGURE_COMMAND
        ""
        BUILD_COMMAND
        cd
        <SOURCE_DIR>/picotcp/
        &&
        sh
        build.sh
        BUILD_IN_SOURCE
        1
        INSTALL_COMMAND
        ""
        EXCLUDE_FROM_ALL
        BUILD_BYPRODUCTS
        "<SOURCE_DIR>/picotcp/build/lib/libpicotcp.a"
        DEPENDS
        get_muslc
    )

    file(
        GLOB
            deps
            ${PICOTCP_PATH}/modules/*.c
            ${PICOTCP_PATH}/modules/*.h
            ${PICOTCP_PATH}/stack/*.c
            ${PICOTCP_PATH}/include/**/*.h
    )

    # Add file dependencies to picotcp
    ExternalProject_Add_StepDependencies(
        picotcp_external
        download
        DEPENDS
        ${PICOTCP_PATH}/Makefile
        DEPENDS
        ${deps}
    )
    # get the dir that the picotcp sources have been copied to by ExternalProject_Add
    ExternalProject_Get_Property(picotcp_external SOURCE_DIR)
    set(BUILD_DIR "${SOURCE_DIR}/picotcp/build/")

    DeclareExternalProjObjectFiles(picotcp_external "${BUILD_DIR}/lib/" FILES "libpicotcp.a")

    # create a library which is the sources
    add_library(picotcp_sources STATIC IMPORTED GLOBAL)
    add_dependencies(picotcp_sources picotcp_external)
    set_property(TARGET picotcp_sources PROPERTY IMPORTED_LOCATION "${BUILD_DIR}/lib/libpicotcp.a")

    # create a library which is the header files, that depends on the sources
    add_library(picotcp INTERFACE)
    add_dependencies(picotcp picotcp_sources)
    set_property(TARGET picotcp PROPERTY INTERFACE_LINK_LIBRARIES picotcp_sources)
    target_include_directories(
        picotcp
        INTERFACE
            "${BUILD_DIR}/include" "$<TARGET_PROPERTY:picotcp_Config,INTERFACE_INCLUDE_DIRECTORIES>"
            "$<TARGET_PROPERTY:sel4_autoconf,INTERFACE_INCLUDE_DIRECTORIES>"
    )
endif()
if(LibPicotcpBsd)
    # find pico tcp location
    find_file(
        PICOTCP_BSD_PATH picotcp-bsd
        PATHS ${CMAKE_SOURCE_DIR}/projects
        CMAKE_FIND_ROOT_PATH_BOTH
    )
    mark_as_advanced(FORCE PICOTCP_BSD_PATH)
    if("${PICOTCP_BSD_PATH}" STREQUAL "PICOTCP_BSD_PATH-NOTFOUND")
        message(
            FATAL_ERROR
                "Failed to find picotcp-bsd. Consider cmake -DPICOTCP_BSD_PATH=/path/to/picotcp-bsd"
        )
    endif()

    add_definitions(-DSTDSOCKET)
    add_definitions(-U__linux__)
    add_definitions(-D_SYS_POLL_H)

    # create picotcp_bsd library
    add_library(
        picotcp_bsd
        STATIC
        EXCLUDE_FROM_ALL
        ${PICOTCP_BSD_PATH}/pico_bsd_sockets.c
        ${PICOTCP_BSD_PATH}/pico_osal_noos.c
    )
    target_include_directories(picotcp_bsd PUBLIC ${PICOTCP_BSD_PATH})
    target_link_libraries(picotcp_bsd muslc picotcp picotcp_Config sel4_autoconf)
endif()
